package gossip.v2.core;

import gossip.v2.GossipCore;
import gossip.v2.cluster.ExponentialBackoff;
import gossip.v2.cluster.GossipNode;
import gossip.v2.message.HandshakeMessage;
import gossip.v2.protocol.GossipHeartHandler;
import gossip.v2.protocol.GossipMessageProcessor;
import gossip.v2.protocol.GossipProtocol;
import org.ricks.ioc.utils.Logger;
import org.ricks.net.StateMachineEnum;
import org.ricks.net.transport.AioQuickClient;
import org.ricks.net.transport.AioSession;

import java.util.Map;
import java.util.concurrent.TimeUnit;

public class ReconnectContext {

    private final GossipCore core;
    private final ExponentialBackoff backoff;
    private final AioQuickClient client;
    private final ReconnectPlugin plugin;
    private final String nodeId;

    public ReconnectContext(GossipNode node, GossipCore core) {
        this.core = core;
        this.nodeId = node.getNodeId();
        this.backoff = new ExponentialBackoff(1000, 60000);
        GossipMessageProcessor gossipMessageProcessor = new GossipMessageProcessor(core);
        // 创建客户端实例
        this.client = new AioQuickClient(node.getIp(), node.getPort(), new GossipProtocol(core), gossipMessageProcessor);

        // 绑定重连插件
        this.plugin = new ReconnectPlugin(client) {
            @Override
            public void stateEvent(StateMachineEnum state, AioSession session, Throwable throwable) {
                if (state == StateMachineEnum.SESSION_CLOSED) {
                    // 重连失败时触发下一次尝试
                    scheduleNextAttempt();

                } else if (state == StateMachineEnum.NEW_SESSION) {
                    // 重连成功回调
                    core.getTransport().onReconnectSuccess(nodeId, session);
                }
            }
        };
        gossipMessageProcessor.addPlugin(plugin);
        // 添加心跳插件
        gossipMessageProcessor.addPlugin(new GossipHeartHandler(2000, 5000, TimeUnit.MILLISECONDS, core));
        client.connectTimeout(3000);
    }

    public void scheduleNextAttempt() {
        if (core.isStopping()) return;

        try {
            long delay = backoff.getCurrentDelay();
            core.getScheduler().schedule(() -> {
                try {
                    client.start();
                } catch (Exception e) {
                    Logger.debug("Reconnect to {} failed: {}", nodeId, e.getMessage());
                    scheduleNextAttempt(); // 继续重试
                }
            }, delay, TimeUnit.MILLISECONDS);
        } catch (Exception e) {
            Logger.error("Scheduling reconnect failed: {}",e, e.getMessage());
        }
    }

    // 新增方法：触发握手
    public void sendHandshake(AioSession session) {
        Map<String, GossipNode> knownNodes = core.getClusterManager().getAllKnownNodesWithAddress();
        HandshakeMessage handshake = new HandshakeMessage(
                core.getLocalNode(),
                knownNodes,
                HandshakeMessage.HandshakeType.REQUEST
        );
        core.getTransport().sendDirect(session, handshake);
    }


    public void shutdown() {
        plugin.shutdown();
        try {
            client.shutdown();
        } catch (Exception ignored) {}
    }
}
